package com.bckj.fastboot.core.page;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bckj.fastboot.core.lang.model.PageResult;
import com.bckj.fastboot.core.util.WebUtils;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * PageSupport
 */
public class PageSupport {

	/**
	 * 构建PageHelper分页
	 */
	public static <T> PageResult<T> buildPage(List<T> list){
		long total = new PageInfo<>(list).getTotal();
		return PageResult.<T>builder()
				.items(list)
				.total(new BigInteger(String.valueOf(total)))
				.build();
	}

	/**
	 * 构建Mybatis-Plus分页
	 */
	public static <T> IPage<T> buildPage() {
		HttpServletRequest request = WebUtils.getRequest();
		Assert.notNull(request, "HttpServletRequest must not be null");
		String page = request.getParameter("page");
		if (page == null || page.isBlank()) {
			page = request.getParameter("pageNum");
		}
		if (page != null && page.matches("^\\d+$")) {
			Integer pageSize = Optional.ofNullable(request.getParameter("pageSize"))
					.map(Integer::parseInt).orElse(20);
			Integer total  = Optional.ofNullable(request.getParameter("total"))
					.map(Integer::parseInt).orElse(0);
			boolean searchCount = Optional.ofNullable(request.getParameter("searchCount"))
					.map(Boolean::parseBoolean).orElse(true);
			Page<T> result = new Page<>(Integer.parseInt(page), pageSize, total, searchCount);
			String orderByParam = request.getParameter("sort");
			if (StringUtils.isNotBlank(orderByParam)) {
				String isAsc = Optional.ofNullable(request.getParameter("asc")).orElse("1");
				if (Objects.equals("1", isAsc)) {
					result.addOrder(OrderItem.asc(orderByParam));
				} else {
					result.addOrder(OrderItem.desc(orderByParam));
				}
			}
			return result;
		}
		// 默认分页
		return new Page<>();
	}

	/**
	 * 构建分页
	 * FastPaginationInnerInterceptor + PageContext
	 */
	public static <T> IPage<T> page(IPage<T> page, Supplier<List<T>> supplier) {
		PageContext.setPage(page);
		try {
			page.setRecords(supplier.get());
		} finally {
			PageContext.remove();
		}
		return page;
	}

	/**
	 * 构建分页
	 * 从请求中获取分页参数
	 */
	public static <T> IPage<T> page(Supplier<List<T>> supplier) {
		return page(buildPage(), supplier);
	}

	public static <T, Q> IPage<T> page(IPage<T> page, Q query, Function<Q, List<T>> function) {
		PageContext.setPage(page);
		try {
			page.setRecords(function.apply(query));
		} finally {
			PageContext.remove();
		}
		return page;
	}

	public static <T, Q> IPage<T> page(Q query, Function<Q, List<T>> function) {
		return page(buildPage(), query, function);
	}

	public static <T, Q> IPage<T> page(Pageable page, Q query, Function<Q, List<T>> function) {
		return page(convert(page), query, function);
	}

	public static Pageable buildPageable() {
		HttpServletRequest request = WebUtils.getRequest();
		Assert.notNull(request, "HttpServletRequest must not be null");
		String page = request.getParameter("page");
		if (page == null || page.isBlank()) {
			page = request.getParameter("pageNum");
		}
		if (page != null && page.matches("^\\d+$")) {
			Integer pageSize = Optional.ofNullable(request.getParameter("pageSize"))
					.map(Integer::parseInt).orElse(20);
			PageRequest result = PageRequest.of(Integer.parseInt(page) - 1, pageSize);
			String orderByParam = request.getParameter("sort");
			if (StringUtils.isNotBlank(orderByParam)) {
				List<Sort.Order> orders = new ArrayList<>();
				String isAsc = Optional.ofNullable(request.getParameter("asc")).orElse("1");
				if (Objects.equals("1", isAsc)) {
					orders.add(Sort.Order.asc(orderByParam));
				} else {
					orders.add(Sort.Order.desc(orderByParam));
				}
				result = result.withSort(Sort.by(orders));
			}
			return result;
		}
		return PageRequest.of(1, 10);
	}


	public static <T> IPage<T> convert(Pageable page) {
		Page<T> result = new Page<>(page.getPageNumber(), page.getPageSize());
		if (page.getSort().isSorted()) {
			page.getSort().stream().forEach(p -> {
				result.addOrder(p.isDescending() ? OrderItem.desc(p.getProperty()) : OrderItem.asc(p.getProperty()));
			});
		}
		return result;
	}
}
